package com.itheima.appserver.service;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.jwt.JWTPayload;
import cn.hutool.jwt.JWTUtil;
import com.alibaba.dubbo.config.annotation.Reference;
import com.itheima.appserver.excepiton.MyException;
import com.itheima.appserver.interceptor.UserThreadLocal;
import com.itheima.commons.autoconfig.template.SmsTemplate;
import com.itheima.commons.constants.Constants;
import com.itheima.commons.model.domain.User;
import com.itheima.commons.model.domain.UserFreeze;
import com.itheima.commons.model.domain.UserLoginRecord;
import com.itheima.commons.model.vo.ErrorResult;
import com.itheima.dubbo.interfaces.UserApi;
import com.itheima.dubbo.interfaces.UserFreezeApi;
import com.itheima.dubbo.interfaces.UserLoginRecordApi;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * User业务类
 */
@Service
public class UserService {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Reference
    private UserApi userApi;

    @Autowired
    private HuanXinService huanXinService;

    @Autowired
    private SmsTemplate smsTemplate;

    @Reference
    private UserLoginRecordApi userLoginRecordApi;

    @Reference
    private UserFreezeApi userFreezeApi;
    /**
     * 发送手机验证码
     *
     * @param phone
     */
    public void sendLoginMsg(String phone) {
        // 判断这个手机号码是否是合法的
        // 如果不合法直接返回错误就可以了
        if (!Validator.isMobile(phone)) {
            // 抛自定义异常
            throw new MyException(ErrorResult.mobileFormatIncorrect());
        }

        // PC端的JS校验 APP端的校验 都是不靠谱的
        // 对于我们后台来说  不要把希望寄托与任何人 一定要自己亲自校验

        // 判断这个人之前是否已经发送过验证码 还没有失效  5
        String code = redisTemplate.opsForValue().get(Constants.SMS_CODE + phone);
        if (!StrUtil.isBlank(code)) {
            // 之前发送过验证码
            throw new MyException(ErrorResult.verificationCodeExpired());
        }

        // 如果是合法的并且之前没有发送过验证码才去发验证码
        // 发送验证码
        // 调用阿里云的平台去发送
        // 生成一个随机的验证码
        /*String randomCode = RandomUtil.randomNumbers(6);
        Boolean result = smsTemplate.sendMsg(phone, Constants.SMS_CODE_TEMPLATE, randomCode);
        if (!result) {
            // 之前发送过验证码
            throw new MyException(ErrorResult.sendMSGError());
        }*/

        String randomCode = "123456";
        // 把验证码存储到redis中
        redisTemplate.opsForValue().set(Constants.SMS_CODE + phone, randomCode, 5, TimeUnit.MINUTES);
    }

    /**
     * 校验验证码是否正确
     *
     * @param phone
     * @param verificationCode
     * @return
     */
    public Map loginVerification(String phone, String verificationCode) {
        // 先要判断手机号码是否合法
        if (!Validator.isMobile(phone)) {
            // 抛自定义异常
            throw new MyException(ErrorResult.mobileFormatIncorrect());
        }
        // 判断验证码是否一致
        String code = redisTemplate.opsForValue().get(Constants.SMS_CODE + phone);
        if (null == code || null == verificationCode || !code.equals(verificationCode)) {
            throw new MyException(ErrorResult.verificationCodeCheckError());
        }

        // 删除验证码
        redisTemplate.delete(Constants.SMS_CODE + phone);
        // 判断用户是否新用户
        // 如果是新用户  执行新增用户的动作
        User user = userApi.findUserByPhoneNum(phone);
        HashMap<String, Object> hashMap = new HashMap<>();
        //查询用户账户信息 如果是冻结则抛出异常

        // 默认是老用户
        hashMap.put("isNew", false);
        if (ObjectUtil.isNull(user)) {
            hashMap.put("isNew", true);

            // 1. 注册到MySQL
            user = userApi.addUser(User.builder()
                    .mobile(phone).password(SecureUtil.md5(Constants.INIT_PASSWORD))
                    .created(new Date())
                    .updated(new Date())
                    .build());

            // 2. 给环信发送一个请求 让环信注册一个新用户
            if (!huanXinService.registerUserToHuanxin(user.getId())) {
                throw new MyException(ErrorResult.userRegistrationFailed());
            }
            //保存用户账户信息
            UserFreeze newUserFreeze = new UserFreeze();
            newUserFreeze.setUserId(Convert.toInt(user.getId()));
            newUserFreeze.setUserStatus("1");
            userFreezeApi.saveUserFreeze(newUserFreeze);

            //记录用户的登录信息
            UserLoginRecord userLoginRecord = new UserLoginRecord();
            userLoginRecord.setUserId(user.getId());
            userLoginRecord.setLogtime(new Date());
            userLoginRecord.setPlace("杭州");
            userLoginRecord.setEquipment("安卓");
            userLoginRecordApi.saveUserLoginRecordApi(userLoginRecord);
        }else {
            UserFreeze userFreeze = userFreezeApi.queryUserFreezeById(user.getId());
            String userStatus = userFreeze.getUserStatus();
            String freezeRange = userFreeze.getFreezeRange();
            if ("2".equals(userStatus)||"1".equals(freezeRange)){
                throw new MyException(ErrorResult.accountFreeze());
            }
            //记录用户的登录信息
            UserLoginRecord userLoginRecord = new UserLoginRecord();
            userLoginRecord.setUserId(user.getId());
            userLoginRecord.setLogtime(new Date());
            userLoginRecord.setPlace("杭州");
            userLoginRecord.setEquipment("安卓");
            userLoginRecordApi.saveUserLoginRecordApi(userLoginRecord);
        }

        // 生成Token
        Map<String, Object> map = new HashMap<>();
        map.put("uid", user.getId());
        map.put("phoneNum", user.getMobile());
        map.put(JWTPayload.EXPIRES_AT, DateTime.of(System.currentTimeMillis() + Constants.JWT_TIME_OUT));
        String token = JWTUtil.createToken(map, Constants.JWT_SECRET.getBytes());

        hashMap.put("token", token);
        return hashMap;

    }


    /**
     * 更新用户的新手机号码
     *
     * @param userId
     * @param newPhone
     */
    public void updatePhone(Long userId, String newPhone) {
        // 先判断新手机号码是否已经被占用
        User newPhoneUser = userApi.findUserByPhoneNum(newPhone);
        if (ObjectUtil.isNotEmpty(newPhoneUser)) {
            throw new MyException(ErrorResult.newPhoneNumISAlreadyOccupied());
        }
        // 更新手机号码
        userApi.updateUserPhoneNum(userId, newPhone);
    }
}
